#include "cy_pdl.h"
#include "cyhal.h"
#include "cybsp.h"
#include "cy_retarget_io.h"

#define VPLUS_CHANNEL_0  (P10_0)
/* Conversion factor */
#define MICRO_TO_MILLI_CONV_RATIO        (1000u)

/* Acquistion time in nanosecond */
#define ACQUISITION_TIME_NS              (116680u)

/* ADC Scan delay in millisecond */
#define ADC_SCAN_DELAY_MS                (200u)


/*******************************************************************************
*       Enumerated Types
*******************************************************************************/
/* ADC Channel constants*/
enum ADC_CHANNELS
{
  CHANNEL_0 = 0,
  NUM_CHANNELS
} adc_channel;

/*******************************************************************************
* Global Variables
*******************************************************************************/
/* ADC Object */
cyhal_adc_t adc_obj;

/* ADC Channel 0 Object */
cyhal_adc_channel_t adc_chan_0_obj;

/* Default ADC configuration */
const cyhal_adc_config_t adc_config = {
        .continuous_scanning=false, // Continuous Scanning is disabled
        .average_count=1,           // Average count disabled
        .vref=CYHAL_ADC_REF_VDDA,   // VREF for Single ended channel set to VDDA
        .vneg=CYHAL_ADC_VNEG_VSSA,  // VNEG for Single ended channel set to VSSA
        .resolution = 12u,          // 12-bit resolution
        .ext_vref = NC,             // No connection
        .bypass_pin = NC };       // No connection

/* Asynchronous read complete flag, used in Event Handler */
static bool async_read_complete = true;
#define NUM_SCAN                    (1024)
#define NUM_CHANNELS                (1)
/* Variable to store results from multiple channels during asynchronous read*/
int32_t result_arr[NUM_CHANNELS * NUM_SCAN] = {0};

float fft_i[NUM_SCAN];
float fft_o[NUM_SCAN];

static void adc_event_handler(void* arg, cyhal_adc_event_t event)
{
    if(0u != (event & CYHAL_ADC_ASYNC_READ_COMPLETE))
    {
        /* Set async read complete flag to true */
        async_read_complete = true;
    }
}

int adc_init(void)
{
    /* Variable to capture return value of functions */
    cy_rslt_t result;

    /* Initialize ADC. The ADC block which can connect to the channel 0 input pin is selected */
    result = cyhal_adc_init(&adc_obj, VPLUS_CHANNEL_0, NULL);
    if(result != CY_RSLT_SUCCESS)
    {
        printf("ADC initialization failed. Error: %ld\n", (long unsigned int)result);
        CY_ASSERT(0);
    }

    /* ADC channel configuration */
    const cyhal_adc_channel_config_t channel_config = {
            .enable_averaging = false,  // Disable averaging for channel
            .min_acquisition_ns = ACQUISITION_TIME_NS, // Minimum acquisition time set to 1us
            .enabled = true };          // Sample this channel when ADC performs a scan

    /* Initialize a channel 0 and configure it to scan the channel 0 input pin in single ended mode. */
    result  = cyhal_adc_channel_init_diff(&adc_chan_0_obj, &adc_obj, VPLUS_CHANNEL_0,
                                          CYHAL_ADC_VNEG, &channel_config);
    if(result != CY_RSLT_SUCCESS)
    {
        printf("ADC first channel initialization failed. Error: %ld\n", (long unsigned int)result);
        CY_ASSERT(0);
    }

     /* Subscribe to the async read complete event to process the results */
     cyhal_adc_enable_event(&adc_obj, CYHAL_ADC_ASYNC_READ_COMPLETE, CYHAL_ISR_PRIORITY_DEFAULT, true);

     printf("ADC is configured in multichannel configuration.\r\n\n");
     printf("Channel 0 is configured in single ended mode, connected to the \r\n");
     printf("channel 0 input pin. Provide input voltage at the channel 0 input pin \r\n");

     //arm_status status = arm_rfft_fast_init_f32(&S,NUM_SCAN);
     //if(status != ARM_MATH_SUCCESS )
     //{
     //	 printf("fft init err\r\n");
     //}
     return 0;
}

int adc_samp(int32_t* buffer, int32_t len)
{
    /* Variable to capture return value of functions */
    cy_rslt_t result;

    /* Variable to store ADC conversion result from channel 0 */
    //int32_t adc_result_0 = 0;


        /* Clear async read complete flag */
        async_read_complete = false;
        /* Register a callback to handle asynchronous read completion */
         cyhal_adc_register_callback(&adc_obj, &adc_event_handler, buffer);

        /* Initiate an asynchronous read operation. The event handler will be called
         * when it is complete. */
        //memset(result_arr,0,sizeof(result_arr));
        cyhal_gpio_write_internal(CYBSP_USER_LED,true);
        result = cyhal_adc_read_async_uv(&adc_obj, len, buffer);
        if(result != CY_RSLT_SUCCESS)
        {
            printf("ADC async read failed. Error: %ld\n", (long unsigned int)result);
            CY_ASSERT(0);
        }
        while(async_read_complete == false);
        cyhal_gpio_write_internal(CYBSP_USER_LED,false);
#if 1
        /*
         * Read data from result list, input voltage in the result list is in
         * microvolts. Convert it millivolts and print input voltage
         *
         */
        for(int i=0; i<len; i++)
        {
            buffer[i] = buffer[i] / MICRO_TO_MILLI_CONV_RATIO;
        }
#endif
#if 0
        for(int i=0; i<NUM_SCAN; i++)
        {
            fft_i[i] = result_arr[i];
        }
        arm_rfft_fast_f32(&S,fft_i,fft_o,0);
        for(int i=0; i<NUM_SCAN/2; i++)
        {
            printf("/*[%f,%fi]*/\r\n", fft_o[2*i],fft_o[2*i+1]);
        }
#endif
    return 0;
}
